﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace Sofire.Data.XSql
{
    internal abstract class XSqlNodeBase : IXSql
    {
        IXSqlDocument IXSql.Document
        {
            get
            {
                return this._Document;
            }
        }
        private XSqlDocument _Document;
        public XSqlDocument Document
        {
            get
            {
                return (XSqlDocument)this._Document;
            }
            set
            {
                this._Document = value;
            }
        }

        private IXSql _Parent;
        public IXSql Parent
        {
            get
            {
                return this._Parent;
            }
            set
            {
                this._Parent = value;
            }
        }

        private IXSql _Previous;
        public IXSql Previous
        {
            get
            {
                return this._Previous;
            }
            set
            {
                this._Previous = value;
            }
        }

        private IXSql _Next;
        public IXSql Next
        {
            get
            {
                return this._Next;
            }
            set
            {
                this._Next = value;
            }
        }

        IXSqlCollection IXSql.Children
        {
            get { return this.Children; }
        }

        private XSqlNodeCollection _Children;
        public XSqlNodeCollection Children
        {
            get
            {
                if(this._Children == null) this._Children = new XSqlNodeCollection();
                return this._Children;
            }
            set
            {
                this._Children = value;
            }
        }

        private string _Xml;
        public string Xml
        {
            get
            {
                return this._Xml;
            }
        }

        public abstract XSqlType Type { get; }

        void IXSql.Load(XmlNode node)
        {
            this._Xml = node.OuterXml;
            this.Load(node);
        }

        internal readonly static char[] XmlEscapes = { '>', '<', '\"', '&' };//'\'',
        protected void CreateXChildren(XElement element)
        {
            if(this._Children == null) return;
            foreach(XSqlNodeBase child in this._Children)
            {
                element.Add(child.CreateXObject());
            }
        }
        public abstract XObject CreateXObject();

        protected abstract void Load(XmlNode node);

        public abstract string Compile(XSqlParameterCollection parameters);

        protected void ThrowException(XSqlError error)
        {
            throw new XSqlException(this, error);
        }

        protected void ThrowExceptionMessage(XSqlError error, string message)
        {
            throw new XSqlException(this, error, message);
        }

        protected void ThrowException(XSqlError error, string attributeName)
        {
            throw new XSqlException(this, error)
            {
                AttributeName = attributeName
            };
        }

        protected string TryGetAttribute(XmlNode node, string attrName)
        {
            var attr = node.Attributes[attrName];
            if(attr == null || string.IsNullOrEmpty(attr.Value)) return null;
            return attr.Value;
        }

        protected string GetAttribute(XmlNode node, string attrName)
        {
            var attr = node.Attributes[attrName];
            if(attr == null || string.IsNullOrEmpty(attr.Value)) this.ThrowException(XSqlError.UnfoundAttribute, attrName);
            return attr.Value;
        }

        public override string ToString()
        {
            return this._Xml ?? base.ToString();
        }
    }
}
